Skip to content
概述
createObject 接收两个数组,将第一个数组的元素作为键、第二个数组中对应索引的元素作为值,组合成一个普通对象。当同一个键出现多次时,保留最先出现的值,后续的值被忽略。
基本概念
- JavaScript 对象的属性名只能是字符串或 Symbol,其他类型的键会在赋值前被转为字符串。
- 使用
key in object可以判断对象自身或其原型链上是否存在某个属性,而不仅仅是值是否为undefined。 - 数组长度不一致时,缺少的值会被填充为
undefined,对应键仍然会出现在结果对象中。
工作原理
函数的核心逻辑:
- 创建一个空对象
res(原型为Object.prototype)。 - 遍历
keysArr,对每个索引i:- 将
keysArr[i]强制转换为字符串,得到key。 - 从
valuesArr[i]取值val(若i超出valuesArr的范围,val为undefined)。 - 若
key不存在于res中(包括原型属性),则执行res[key] = val,否则跳过。
- 将
- 返回
res。
去重策略由 if (!(key in res)) 保证:只有在键完全不存在时才写入,因此首次出现的键值会被保留。如果改用 if (!res[key]),当值为 undefined、null、0、空字符串等假值时,条件会错误成立,从而可能用后续相同键的值覆盖先出现的假值,破坏“保留最先出现值”的规则。
另外,in 操作符会检查原型链,这可能引入意料之外的行为(见“注意点”)。
基本用法
javascript
var createObject = function (keysArr, valuesArr) {
const res = {};
for (let i = 0; i < keysArr.length; i++) {
const key = String(keysArr[i]),
val = valuesArr[i];
if (!(key in res)) res[key] = val;
}
return res;
};简单调用:
javascript
createObject(['a', 'b'], [1, 2]); // { a: 1, b: 2 }命令
在 Node.js 中可以这样快速验证:
bash
node -e "var createObject = function(k,v){const o={};for(let i=0;i<k.length;i++){const key=String(k[i]),val=v[i];if(!(key in o))o[key]=val}return o}; console.log(createObject(['x','y'],[10,20]))"输出:
{ x: 10, y: 20 }示例
键重复:先出现优先
javascript
createObject(['a', 'b', 'a'], [1, 2, 3]); // { a: 1, b: 2 }'a' 第二次出现时,由于 'a' in res 为 true,值 3 被忽略,最终保留 1。
数字键转为字符串
javascript
createObject([1, 2], ['one', 'two']); // { '1': 'one', '2': 'two' }键 1 和 2 经过 String() 处理后变为字符串 '1'、'2'。
null 与 undefined 作为键
javascript
createObject([null, undefined], ['val1', 'val2']);
// { null: 'val1', undefined: 'val2' }String(null) 产生字符串 'null',String(undefined) 产生 'undefined',因此对象中会以这两个字符串作为键。这符合题目要求,但需注意与 null / undefined 原始值本身的语义区别。
值的数组较短
javascript
createObject(['a', 'b', 'c'], [1]); // { a: 1, b: undefined, c: undefined }valuesArr[1] 和 valuesArr[2] 超出数组边界,取值变为 undefined,但键 b、c 依然会被创建。
值为 undefined 仍应保留
javascript
createObject(['key'], [undefined]); // { key: undefined }in 操作符能正确判别 'key' 尚未存在于对象中,因此值为 undefined 的属性会被正常写入。若错误地使用 if (!res[key]) 来判断键的存在性,对于无重复键的情况虽然也能得到 { key: undefined }(因为 !undefined 为 true,会执行赋值),但当同一个键重复出现且先出现的值为 undefined 时,就会暴露问题:
javascript
// 假设实现中误用了 if (!res[key])
createObject(['key', 'key'], [undefined, 'val']); // 得到 { key: 'val' }第二次遇到 'key' 时,res['key'] 为 undefined,!undefined 为 true,导致赋值再次发生,后出现的 'val' 覆盖了先前的 undefined,违背了保留最先出现值的规则。使用 key in res 则可以避免这种覆盖。
原型属性造成的键冲突
javascript
createObject(['toString', 'a'], [1, 2]); // { a: 2 }'toString' in {} 为 true,因为空对象从原型链上继承了 Object.prototype.toString。函数会认为该键已经存在,从而跳过 'toString' 的赋值。若 keysArr 可能包含 toString、valueOf、constructor 等原型属性名,应使用 Object.prototype.hasOwnProperty.call(res, key) 替代 key in res,或者用 Object.create(null) 创建无原型的对象。
注意点
key in res会遍历原型链,因此Object.prototype上的属性名(toString、hasOwnProperty等)会被视为已存在,导致对应的数据键被跳过。如果键集不可控,应当用hasOwnProperty或Object.hasOwn(ES2022)进行安全检查。if (!res[key])无法处理假值(undefined、null、0、false、''),不能用作判断属性是否存在的可靠手段。对于重复键,它会错误地允许后续值覆盖先前的假值。- 所有键都会被转为字符串。如果传入对象作为键,会先调用其
toString()方法,容易得到类似[object Object]的键名。这种强转行为无法在函数内部被绕过。 - 函数不会对参数做类型校验,直接依赖
length和索引访问,因此keysArr和valuesArr可以是任何类数组对象。
限制
- 只能生成以字符串为键的对象。如果希望保留 Symbol 键,该实现无法满足,因为
String(symbol)会变为"Symbol(description)"字符串,失去原本的 Symbol 身份。 - 不涉及深度合并或嵌套结构处理,值会原样赋值。
- 稀疏数组或非数字索引等情况依赖 JavaScript 引擎的默认行为,函数未做额外处理。
应用
该函数适用于将两个平行数组快速组合为映射的场景,例如从表格的字段名数组与对应数据行数组构建临时记录对象,或在前后端约定以数组对齐方式传参时还原为可读的键值结构。
